package cn.geekyspace.scanhive.serial.receiver;

import cn.geekyspace.scanhive.pojo.entity.CleaningData;
import cn.geekyspace.scanhive.service.CleaningDataService;
import cn.geekyspace.scanhive.utils.UIUpdater;
import com.fazecast.jSerialComm.SerialPort;
import javafx.scene.paint.Color;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * PLC 数据接收器
 */
@Slf4j
@Data
@Component
@RequiredArgsConstructor
public class PLCDataReceiver {

    // 使用原子布尔值控制接收线程的状态
    private final AtomicBoolean keepReceiving = new AtomicBoolean(false);

    // 当前处理的串口
    private SerialPort currentPort;

    // 串口接收线程
    private Thread receiveThread;

    // 注入 UI 更新器
    private final UIUpdater uiUpdater;

    // 注入清理数据服务
    private final CleaningDataService cleaningDataService;

    /**
     * 开始接收数据
     */
    public synchronized void startReceivingData(SerialPort port) {
        if (port.isOpen() && !keepReceiving.get()) {
            this.currentPort = port;
            this.keepReceiving.set(true);

            log.info("开始监听PLC串口: {}", port.getSystemPortName());

            receiveThread = new Thread(() -> {
                try (InputStream inputStream = port.getInputStream()) {
                    while (keepReceiving.get() && port.isOpen()) {
                        int available = inputStream.available();
                        if (available == 0) {
                            Thread.sleep(100); // 没有数据可读时休眠
                            continue;
                        }

                        byte[] buffer = new byte[available];
                        int bytesRead = inputStream.read(buffer);
                        if (bytesRead > 0) {
                            StringBuilder hexData = new StringBuilder();
                            for (int i = 0; i < bytesRead; i++) {
                                hexData.append(String.format("%02x", buffer[i]).toUpperCase(Locale.ROOT));
                                if (i < bytesRead - 1) {
                                    hexData.append(" ");
                                }
                            }
                            // ASCII 编码的16进制字符串
                            String asciiHexData = hexData.toString();
                            log.info("PLC接收 ASCII数据: {}", asciiHexData);
                            uiUpdater.setLogMessage("PLC接收 16进制 ASCII数据: " + asciiHexData);  // 7D 00 7E 00 7F 00 80 00 81 00 1E 00

                            CleaningData cleaningData = hexToCleaningData(asciiHexData);

                            log.info("PLC接收 数据转对象: {}", cleaningData);
                            handleReceivedData(cleaningData, asciiHexData);
                        }
                    }
                } catch (InterruptedException e) {
                    log.warn("PLC接收线程被中断: {}", e.getMessage());
                } catch (IOException e) {
                    log.error("PLC读取串口数据时发生错误: {}", e.getMessage());
                } finally {
                    cleanupResources();
                }
            });

            receiveThread.setName("PLC-SerialPort-Receive-Thread");
            receiveThread.start();
        } else {
            log.warn("串口未打开或已经在接收数据: {}", port.getSystemPortName());
        }
    }

    /**
     * 停止接收数据
     */
    public synchronized void stopReceivingData() {
        if (keepReceiving.getAndSet(false)) {
            log.info("正在停止PLC数据接收...");
            if (currentPort != null && currentPort.isOpen()) {
                try {
                    currentPort.closePort();
                    log.info("成功关闭串口: {}", currentPort.getSystemPortName());
                } catch (Exception e) {
                    log.error("关闭串口时发生错误: {}", e.getMessage());
                }
            }
            if (receiveThread != null && receiveThread.isAlive()) {
                receiveThread.interrupt();
            }
        } else {
            log.warn("接收线程已经停止或未启动");
        }
    }

    /**
     * 清理资源
     */
    private synchronized void cleanupResources() {
        if (currentPort != null) {
            if (currentPort.isOpen()) {
                currentPort.closePort();
                log.info("PLC释放串口资源: {}", currentPort.getSystemPortName());
            }
            currentPort = null;
        }
    }

    /**
     * 处理接收到的数据
     */
    private void handleReceivedData(CleaningData data, String asciiHexData) {
        if (data == null) {
            uiUpdater.setLogMessage("PLC无效数据：" + asciiHexData, Color.RED);
            return;
        }

        //uiUpdater.updatePLCText(data);  // 更新 UI 显示的 PLC 数据
        boolean isValid = validatePLCData(data);
        if (isValid) {
            // 等待测试结果的数据
            CleaningData lastWaitingForTestResultData = uiUpdater.getLastWaitingForTestResultData();
            if (lastWaitingForTestResultData != null) {
                data.setId(lastWaitingForTestResultData.getId());
                data.setQrCode(lastWaitingForTestResultData.getQrCode());
                data.setQrCodeScanTime(lastWaitingForTestResultData.getQrCodeScanTime());
                // 更新数据库
                cleaningDataService.receivePlcDataAndUpdate(data);
                uiUpdater.receivePlcDataAndUpdate(data);
                System.out.println(data);
                uiUpdater.setLogMessage("PLC数据处理成功：" + asciiHexData, Color.GREEN);
            } else {
                uiUpdater.setLogMessage("请先扫描二维码后再传PLC数据：" + asciiHexData, Color.RED);
            }
        } else {
            uiUpdater.setLogMessage("PLC数据处理失败：" + asciiHexData, Color.RED);
        }
    }

    /**
     * 验证 PLC 数据的合法性
     */
    private boolean validatePLCData(CleaningData data) {
        // 示例验证逻辑，可根据具体需求修改
        return true;
    }

    /**
     * 十六进制字符串转换为普通字符串
     */
    private CleaningData hexToCleaningData(String hexData) {

        // 解析十六进制数据
        String[] hexArray = hexData.split(" ");
        if (hexArray.length != 12) {
            return null;
        }

        // 高低位互换并解析十进制
        int cleaningDuration = parseHexPair(hexArray[0], hexArray[1]);
        double cleaningTemperature = parseHexPair(hexArray[2], hexArray[3]) / 10.0;
        int rinsingDuration = parseHexPair(hexArray[4], hexArray[5]);
        double rinsingTemperature = parseHexPair(hexArray[6], hexArray[7]) / 10.0;
        int dryingDuration = parseHexPair(hexArray[8], hexArray[9]);
        double dryingTemperature = parseHexPair(hexArray[10], hexArray[11]) / 10.0;
        log.info("PLC接收 十进制数据: {}", cleaningDuration + "秒 " + cleaningTemperature + "℃ " + rinsingDuration + "秒 " + rinsingTemperature + "℃ " + dryingDuration + "秒 " + dryingTemperature + "℃");

        return CleaningData.builder()
                .cleaningDuration(cleaningDuration)         // 清洗时间 31秒
                .cleaningTemperature(cleaningTemperature)    // 清洗温度 50.7℃
                .rinsingDuration(rinsingDuration)          // 漂洗时间 31秒
                .rinsingTemperature(rinsingTemperature)     // 漂洗温度 49.7℃
                .dryingDuration(dryingDuration)           // 烘干时间 11秒
                .dryingTemperature(dryingTemperature)      // 烘干温度 50.7℃
                .plcDataReturnTime(LocalDateTime.now())   // PLC数据回传时间
                .build();
    }

    /**
     * 高低位互换并转换为十进制
     * @param high 高位字节
     * @param low  低位字节
     * @return 解析后的十进制数据
     */
    private int parseHexPair(String high, String low) {
        String swappedHex = low + high; // 高低位互换
        return Integer.parseInt(swappedHex, 16); // 转换为十进制
    }
}
